import * as Cesium from '@cesiumjs';
import * as mobx from 'mobx';
import {
  g3x_defineClassProperties,
} from "@g3x/utils";

export default function(Ctor) {
  g3x_defineClassProperties(Ctor, [{
    key: '_createDirections',
    value: function _createDirections() {
      var _this2 = this;

      // 几何绘制
      this._originHeadingDirection = new Cesium.Cartesian3(1, 0, 0);
      this._originHeadingUp = new Cesium.Cartesian3(0, 0, -1);
      this._originPitchDirection = new Cesium.Cartesian3(1, 0, 0);
      this._originPitchUp = new Cesium.Cartesian3(0, -1, 0);
      this._originRollDirection = new Cesium.Cartesian3(0, 1, 0);
      this._originRollUp = new Cesium.Cartesian3(1, 0, 0);

      this._headingDirection = new Cesium.Cartesian3(1, 0, 0);
      this._headingUp = new Cesium.Cartesian3(0, 0, -1);
      this._pitchDirection = new Cesium.Cartesian3(1, 0, 0);
      this._pitchUp = new Cesium.Cartesian3(0, -1, 0);
      this._rollDirection = new Cesium.Cartesian3(0, 1, 0);
      this._rollUp = new Cesium.Cartesian3(1, 0, 0);

      this._headingHpr = new Cesium.HeadingPitchRoll();
      this._pitchHpr = new Cesium.HeadingPitchRoll();
      this._rollHpr = new Cesium.HeadingPitchRoll();
      this._lastHpr = new Cesium.HeadingPitchRoll();

      this._headingQuat = new Cesium.Quaternion();
      this._pitchQuat = new Cesium.Quaternion();
      this._rollQuat = new Cesium.Quaternion();
      this._lastQuat = new Cesium.Quaternion();

      this._headingMat = new Cesium.Matrix3();
      this._pitchMat = new Cesium.Matrix3();
      this._rollMat = new Cesium.Matrix3();
      this._lastMat = new Cesium.Matrix3();

      this._headingMat4 = new Cesium.Matrix4();
      this._pitchMat4 = new Cesium.Matrix4();
      this._rollMat4 = new Cesium.Matrix4();
      this._lastMat4 = new Cesium.Matrix4();

      function updateDirections() {
        // this._headingHpr.heading = this.rotation[0];
        _this2._pitchHpr.heading = _this2.rotation[0];

        _this2._rollHpr.heading = _this2.rotation[0];
        _this2._rollHpr.pitch = _this2.rotation[1];

        _this2._lastHpr.heading = _this2.rotation[0];
        _this2._lastHpr.pitch = _this2.rotation[1];
        _this2._lastHpr.roll = _this2.rotation[2];

        _this2._headingQuat = Cesium.Quaternion.fromHeadingPitchRoll(_this2._headingHpr, _this2._headingQuat);
        _this2._pitchQuat = Cesium.Quaternion.fromHeadingPitchRoll(_this2._pitchHpr, _this2._pitchQuat);
        _this2._rollQuat = Cesium.Quaternion.fromHeadingPitchRoll(_this2._rollHpr, _this2._rollQuat);
        _this2._lastQuat = Cesium.Quaternion.fromHeadingPitchRoll(_this2._lastHpr, _this2._lastQuat);

        _this2._headingMat = Cesium.Matrix3.fromQuaternion(_this2._headingQuat, _this2._headingMat);
        _this2._pitchMat = Cesium.Matrix3.fromQuaternion(_this2._pitchQuat, _this2._pitchMat);
        _this2._rollMat = Cesium.Matrix3.fromQuaternion(_this2._rollQuat, _this2._rollMat);
        _this2._lastMat = Cesium.Matrix3.fromQuaternion(_this2._lastQuat, _this2._lastMat);

        _this2._headingMat4 = Cesium.Matrix4.multiplyByMatrix3(_this2._enu, _this2._headingMat, _this2
          ._headingMat4);
        _this2._pitchMat4 = Cesium.Matrix4.multiplyByMatrix3(_this2._enu, _this2._pitchMat, _this2._pitchMat4);
        _this2._rollMat4 = Cesium.Matrix4.multiplyByMatrix3(_this2._enu, _this2._rollMat, _this2._rollMat4);
        _this2._lastMat4 = Cesium.Matrix4.multiplyByMatrix3(_this2._enu, _this2._lastMat, _this2._lastMat4);

        Cesium.Matrix3.multiplyByVector(_this2._headingMat, _this2._originHeadingDirection, _this2
          ._headingDirection);
        Cesium.Matrix3.multiplyByVector(_this2._headingMat, _this2._originHeadingUp, _this2._headingUp);
        Cesium.Matrix3.multiplyByVector(_this2._pitchMat, _this2._originPitchDirection, _this2._pitchDirection);
        Cesium.Matrix3.multiplyByVector(_this2._pitchMat, _this2._originPitchUp, _this2._pitchUp);
        Cesium.Matrix3.multiplyByVector(_this2._rollMat, _this2._originRollDirection, _this2._rollDirection);
        Cesium.Matrix3.multiplyByVector(_this2._rollMat, _this2._originRollUp, _this2._rollUp);

        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._headingDirection, _this2._headingDirection);
        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._headingUp, _this2._headingUp);
        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._pitchDirection, _this2._pitchDirection);
        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._pitchUp, _this2._pitchUp);
        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._rollDirection, _this2._rollDirection);
        Cesium.Matrix4.multiplyByPointAsVector(_this2._enu, _this2._rollUp, _this2._rollUp);
      };

      this.disposers.push(mobx.reaction(function() {
        return _this2.rotation;
      }, function() {
        updateDirections();
      }));

      this.disposers.push(this._enuChangedEvent.addEventListener(function() {
        updateDirections();
      }));
    }
  }, {
    key: '_createCenterModel',
    value: function _createCenterModel() {
      var _this3 = this;

      this._cameraHelper = new _CameraHelper2.default(this._earth);

      this.disposers.push(function() {
        _this3._cameraHelper = _this3._cameraHelper && _this3._cameraHelper.destroy();
      });

      this.disposers.push((0, _mobx.reaction)(() => {
        return {
          position: _this3.position,
          rotation: _this3.rotation
        };
      }, () => {
        _this3._cameraHelper.position = _this3.position;
        const [r, s, t] = _this3.rotation;
        _this3._cameraHelper.rotation = [r + Cesium.Math.PI_OVER_TWO, s, t];
      }));

      this.disposers.push(mobx.autorun(function() {
        _this3._cameraHelper.show = _this3.enabled;
      }));
    }
  }, {
    key: '_createBaseCircles',
    value: function _createBaseCircles() {
      var _this4 = this;
      this._baseCircles = Array(3).keys().map((i) => {
        return new _Circle2.default(_this4._earth);
      });
      this.disposers.push(function() {
        _this4._baseCircles.forEach(function(c) {
          c.destroy();
        });
        _this4._baseCircles.length = 0;
      });

      var baseCircleMatrix = Array(3).keys().map(
        function() {
          return new Cesium.Matrix4();
        });

      function updateCircles() {
        Cesium.Matrix4.clone(_this4._headingMat4, baseCircleMatrix[0]);
        Cesium.Matrix4.multiply(_this4._pitchMat4, Cesium.Axis.Y_UP_TO_Z_UP, baseCircleMatrix[1]);
        Cesium.Matrix4.multiply(_this4._rollMat4, Cesium.Axis.X_UP_TO_Z_UP, baseCircleMatrix[2]);

        Cesium.Matrix4.toArray(baseCircleMatrix[0], _this4._baseCircles[0].modelMatrix);
        Cesium.Matrix4.toArray(baseCircleMatrix[1], _this4._baseCircles[1].modelMatrix);
        Cesium.Matrix4.toArray(baseCircleMatrix[2], _this4._baseCircles[2].modelMatrix);
      };
      updateCircles();
      this.disposers.push(mobx.reaction(function() {
        return _this4.rotation;
      }, updateCircles));

      this.disposers.push(this._enuChangedEvent.addEventListener(updateCircles));

      this.disposers.push(mobx.autorun(function() {
        _this4._realSceneScale && _this4._baseCircles.forEach(function(c) {
          c.scale = _this4._realSceneScale * 2.0;
        });
      }));

      var colors = [
        [1, 0, 0, 1],
        [0, 1, 0, 1],
        [0, 0, 1, 1]
      ];

      function updateColors(_ref2) {
        var actives = _ref2.actives;

        _this4._baseCircles[0].baseRotation = _this4.isCameraLike ? Math.PI * 0.5 : 0.0;

        _this4._baseCircles.forEach(function(c, i) {
          // heading 和 roll 需要去负值，通过magic来处理
          var magic = i % 2 === 0 ? -1 : 1;
          if (actives[i]) {
            // console.log('yellow');
            c.color.splice(0, 4, 1, 1, 0, 1);
            // c.startRotation = magic * this._startRotation[i];
            // c.endRotation = magic * this._endRotation[i];

            var startRotation = magic * _this4._startRotation[i];
            var endRotation = magic * _this4._endRotation[i];

            // roll需要特殊处理以下，因为获得的数据差90度
            if (i === 2) {
              startRotation += Math.PI * 0.5;
              endRotation += Math.PI * 0.5;
            }

            c.startRotation = startRotation;
            c.endRotation = endRotation;
          } else {
            // console.log(`red ${colors[i].toString()}`);
            // c.color.splice(0, 4, ...colors[i]);
            c.color = [...colors[i]];
            c.startRotation = 0.0;
            c.endRotation = 0.0;
          }
          c.rotation = magic * _this4.rotation[i];
        });
      };

      updateColors({
        actives: [this.headingCircleActive, this.pitchCircleActive, this.rollCircleActive]
      });

      this.disposers.push(mobx.reaction(function() {
        return {
          actives: [_this4.headingCircleActive, _this4.pitchCircleActive, _this4.rollCircleActive],
          rotation: _this4.rotation,
          startRotation: _this4._startRotation,
          endRotation: _this4._endRotation
        };
      }, updateColors));

      function updateBaseCircles3() {
        if (_this4._baseCircles) {
          _this4._baseCircles.forEach(function(c) {
            c.show = _this4.enabled;
          });
        }
      };

      updateBaseCircles3();

      this.disposers.push(mobx.reaction(function() {
        return _this4.enabled;
      }, updateBaseCircles3));
    }
  }, {
    key: '_init',
    value: function _init() {
      var _this5 = this;

      // 放在此处会有问题，_init实在mobx.observe的回调中执行的，会导致_createBaseCircles函数中的reaction调用异常！
      // // 如果放在构造函数中，会导致circle构造出现问题
      // if (!this._baseCircles) {
      //     this._createBaseCircles();
      // }

      var lastMmPositon = {
        x: 0,
        y: 0
      };
      var eventSource = this._earth.eventSource;
      this.mouseMove$ = this.mouseMove$ || rxjs.merge(eventSource.mouse.mouseMove, eventSource
        .cameraChanged.pipe(rxjs.operators.throttleTime(100))).pipe(rxjs.operators.map(function(movement) {
        if (movement && movement.endPosition) {
          lastMmPositon.x = movement.endPosition.x;
          lastMmPositon.y = movement.endPosition.y;
          return movement.endPosition;
        } else {
          return lastMmPositon;
        }
      }));
      this.leftClick$ = this.leftClick$ || eventSource.mouse.leftClick.pipe(rxjs.operators.map(function(
        movement) {
        return movement.position;
      }));
      this.rightClick$ = this.rightClick$ || eventSource.mouse.rightClick;

      var scene = this._earth.czm.scene;
      this._stepsOp = this._stepsOp || [
        [this.mouseMove$, function(windowCoordinates) {
          _this5._step1(scene, windowCoordinates);
        }, this.leftClick$, function(windowCoordinates) {
          _this5._step1(scene, windowCoordinates);

          if (_this5.headingCircleActive || _this5.pitchCircleActive || _this5.rollCircleActive) {
            var _oldRotation;

            // this.position.forEach((value, index) => this._oldPosition[index] = value);
            // this._oldScale = this._realSceneScale;

            (_oldRotation = _this5._oldRotation).splice.apply(_oldRotation, [0, 3, ..._this5.rotation]);

            _this5._step2(scene, windowCoordinates); // 执行下，更新下_originPosition2，否则虚线位置不对
            _this5._steps.next();
          }
        }, this.rightClick$, function() {
          _this5._steps.enabled = false;
        }],
        [this.mouseMove$, function(windowCoordinates) {
          _this5._step2(scene, windowCoordinates);
        }, this.leftClick$, function(windowCoordinates) {
          _this5._step2(scene, windowCoordinates);

          _this5.headingCircleActive = false;
          _this5.pitchCircleActive = false;
          _this5.rollCircleActive = false;
          _this5._steps.goto(0);
        }, this.rightClick$, function() {
          _this5._steps.enabled = false;
        }]
      ];

      if (!this._steps) {
        this._steps = new _XbsjSteps2.default(this._earth, this._stepsOp);
      }
    }
  }, {
    key: '_step2',
    value: function _step2(scene, windowCoordinates) {
      var tolerance = this._realSceneScale / this.fixScreenSize * this.toleranceSize;

      if (this.headingCircleActive) {
        var heading = this._getActiveAngle(scene, windowCoordinates, tolerance, this._headingUp, this
          ._headingDirection, true);

        if (typeof heading !== 'undefined') {
          this._endRotation[0] = heading;
          this.rotation[0] = Cesium.Math.negativePiToPi(this._endRotation[0] - this._startRotation[0] +
            this._oldRotation[0]);
        }
        return;
      }

      if (this.pitchCircleActive) {
        var pitch = this._getActiveAngle(scene, windowCoordinates, tolerance, this._pitchUp, this
          ._pitchDirection, true);

        if (typeof pitch !== 'undefined') {
          this._endRotation[1] = pitch;
          this.rotation[1] = Cesium.Math.negativePiToPi(this._endRotation[1] - this._startRotation[1] +
            this._oldRotation[1]);
        }
        return;
      }

      if (this.rollCircleActive) {
        var roll = this._getActiveAngle(scene, windowCoordinates, tolerance, this._rollUp, this
          ._rollDirection, true);

        if (typeof roll !== 'undefined') {
          this._endRotation[2] = roll;
          this.rotation[2] = Cesium.Math.negativePiToPi(this._endRotation[2] - this._startRotation[2] +
            this._oldRotation[2]);
        }
        return;
      }
    }
  }, {
    key: '_computeAngle',
    value: function _computeAngle(dir1, dir2, up) {
      this._scratchComputeAngleDir1 = this._scratchComputeAngleDir1 || new Cesium.Cartesian3();
      this._scratchComputeAngleDir2 = this._scratchComputeAngleDir2 || new Cesium.Cartesian3();
      this._scrtachComputeAngleUp = this._scrtachComputeAngleUp || new Cesium.Cartesian3();

      dir1 = Cesium.Cartesian3.normalize(dir1, this._scratchComputeAngleDir1);
      dir2 = Cesium.Cartesian3.normalize(dir2, this._scratchComputeAngleDir2);

      var angle = Math.acos(Cesium.Cartesian3.dot(dir1, dir2));
      var up2 = Cesium.Cartesian3.cross(dir1, dir2, this._scrtachComputeAngleUp);
      if (Cesium.Cartesian3.dot(up2, up) < 0) {
        angle = -angle;
      }

      return angle;
    }
  }, {
    key: '_getActiveAngle',
    value: function _getActiveAngle(scene, windowCoordinates, tolerance, up, direction) {
      var ignoreDistance = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;

      this._scratchUpdateActivesCartesian = this._scratchUpdateActivesCartesian || new Cesium
        .Cartesian3();
      var cartesian = (0, _pickVirtualPlane2.default)(scene, this._centerCartesian, up,
        windowCoordinates, this._scratchUpdateActivesCartesian);
      if (cartesian) {
        var dir = Cesium.Cartesian3.subtract(cartesian, this._centerCartesian, cartesian);
        if (!ignoreDistance) {
          var d = Cesium.Cartesian3.magnitude(dir);
          if (Math.abs(d - this._realSceneScale) < tolerance) {
            return this._computeAngle(direction, dir, up);
          }
        } else {
          return this._computeAngle(direction, dir, up);
        }
      }

      return undefined;
    }
  }, {
    key: '_step1',
    value: function _step1(scene, windowCoordinates) {
      var tolerance = this._realSceneScale / this.fixScreenSize * this.toleranceSize;

      this.headingCircleActive = false;
      this.pitchCircleActive = false;
      this.rollCircleActive = false;

      var heading = this._getActiveAngle(scene, windowCoordinates, tolerance, this._headingUp, this
        ._headingDirection, false);

      if (typeof heading !== 'undefined') {
        this._startRotation[0] = heading;
        this._endRotation[0] = heading;
        this.headingCircleActive = true;

        return;
      }

      var pitch = this._getActiveAngle(scene, windowCoordinates, tolerance, this._pitchUp, this
        ._pitchDirection, false);

      if (typeof pitch !== 'undefined') {
        this._startRotation[1] = pitch;
        this._endRotation[1] = pitch;
        this.pitchCircleActive = true;

        return;
      }

      var roll = this._getActiveAngle(scene, windowCoordinates, tolerance, this._rollUp, this
        ._rollDirection, false);

      if (typeof roll !== 'undefined') {
        this._startRotation[2] = roll;
        this._endRotation[2] = roll;
        this.rollCircleActive = true;

        return;
      }
    }
  }, {
    key: '_start',
    value: function _start() {
      var _this6 = this;

      this._init();
      if (this._stepsDisable) {
        throw new Error('_stepsDisable should not exists!');
      }
      this._stepsDisable = _XbsjEditing3.default.enableProperty(this._steps, function() {
        return _this6.enabled = false;
      });
    }
  }, {
    key: '_cancel',
    value: function _cancel() {
      this._stepsDisable = this._stepsDisable && this._stepsDisable();
    }
  }, {
    key: 'destroy',
    value: function destroy() {
      this.enabled = false;
      return (0, _get3.default)(CirclesRotating.prototype.__proto__ || (0, _getPrototypeOf2.default)(
        CirclesRotating.prototype), 'destroy', this).call(this);
    }
  }]);
}
